﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using Org.BouncyCastle.Asn1.X509;
using Polly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.SignalR;

namespace EcoSystem
{
    /// <summary>
    /// 
    /// </summary>
    [Authorize]
    public class MessagingHub : AbpHub, IMessagingHubAppService
    {
        private readonly IHubContext<MessagingHub> context;

        public INotificationAppService NotificationService { get; set; }

        public MessagingHub(IHubContext<MessagingHub> hubContext)
        {
            context = hubContext;
        }

        public async Task ClearAllAsync()
        {
            string userId = CurrentUser.Id.ToString();
            await NotificationService.ClearAllAsync();
            await context.Clients.User(CurrentUser.Id.ToString())
          .SendAsync("ReceiveMessage", "ClearAll");
        }
        public async Task ReadAllAsync()
        {
            string userId = CurrentUser.Id.ToString();
            await NotificationService.ReadAllAsync();
            var type = HubMessageType.Silent.ToString();
            var message = new SilentMessageDto { Message = "已全部设置为已读" };
            await context.Clients.User(userId).SendAsync("ReceiveMessage", type, message);
        }
        public async Task SetReadAsync(Guid id)
        {
            await NotificationService.SetReadAsync(id);
            var type = HubMessageType.Silent.ToString();
            var message = new SilentMessageDto
            {
                Message = "已设置为已读",
                Payload = new
                {
                    id = id
                }
            };
            await context.Clients.User(CurrentUser.Id.ToString()).SendAsync("ReceiveMessage", type, message);
        }

        public async Task GetNotificationsAsync()
        {
            var startDate = DateTime.Today.AddDays(-3);
            var items = await NotificationService.GetAllListAsync(new GetNotificationInput()
            {
                StartTime = startDate
            });
            string userId = CurrentUser.Id.ToString();
            await context.Clients.User(userId).SendAsync("ReceiveMessage", "Notifications", items);
        }

        public async Task SendMessageAsync(HubMessageDto message)
        {
            var userIds = message.UserIds.Select(x => x.ToString());
            var type = message.MessageType.ToString();
            await context.Clients.Users(userIds).SendAsync("ReceiveMessage", type, message.Payload);
        }

        public async Task InvokeMethodAsync(List<Guid> userIds, string method, object[] args)
        {
            var ids = userIds.Select(x => x.ToString()).ToList();
            if (args.Length == 0)
            {
                await context.Clients.Users(ids).SendAsync(method);
            }
            else if (args.Length == 1)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0]);
            }
            else if (args.Length == 2)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1]);
            }
            else if (args.Length == 3)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2]);
            }
            else if (args.Length == 4)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3]);
            }
            else if (args.Length == 5)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4]);
            }
            else if (args.Length == 6)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4], args[5]);
            }
            else if (args.Length == 7)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
            }
            else if (args.Length == 8)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
            }
            else if (args.Length == 9)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
            }
            else if (args.Length == 10)
            {
                await context.Clients.Users(ids).SendAsync(method, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
            }
            else
            {
                await context.Clients.Users(ids).SendAsync(method, args);
            }
        }

        public async Task SendNotificationAsync(HubNotificationDto notification)
        {
            var setting = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
            var type = HubMessageType.Notification.ToString();
            if (notification.UserId.HasValue && notification.UserId != Guid.Empty)
            {
                var userId = notification.UserId.Value.ToString();
                var result = await NotificationService.CreateAsync(new CreateOrUpdateNotificationDto()
                {
                    Data = JsonConvert.SerializeObject(notification.Data, setting),
                    Description = notification.Description,
                    IsRead = false,
                    TargetId = notification.TargetId,
                    Title = notification.Title,
                    Type = notification.Type,
                    Url = notification.Url,
                    UserId = notification.UserId.Value,
                    ExtraProperties = notification.ExtraProperties
                });
                await context.Clients.User(userId).SendAsync("ReceiveMessage", type, result);
            }
            else
            {
                await context.Clients.All.SendAsync("ReceiveMessage", type, notification);
            }
        }


        public async Task SendSilentMessageAsync(object data, Guid[] userIds)
        {
            var ids = userIds.Select(x => x.ToString());
            var type = HubMessageType.Silent.ToString();
            await context.Clients.Users(ids).SendAsync("ReceiveMessage", type, data);
        }

        public async Task SendNotificationsAsync(List<HubNotificationDto> notifications)
        {
            var setting = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
            var type = HubMessageType.Notification.ToString();
            var userIds = notifications.Select(x => x.UserId.ToString()).ToList();
            var items = new List<CreateOrUpdateNotificationDto>();
            foreach (var item in notifications)
            {
                if (item.UserId != null && item.UserId != Guid.Empty)
                {
                    items.Add(new CreateOrUpdateNotificationDto()
                    {
                        Data = JsonConvert.SerializeObject(item.Data),
                        Description = item.Description,
                        IsRead = false,
                        TargetId = item.TargetId,
                        Title = item.Title,
                        Type = item.Type,
                        Url = item.Url,
                        UserId = item.UserId.Value,
                        ExtraProperties = item.ExtraProperties
                    });
                }
                else
                {
                    await context.Clients.All.SendAsync("ReceiveMessage", type, item);
                }
            }
            var dtos = await NotificationService.CreateManyAsync(items);
            foreach (var item in dtos)
            {
                await context.Clients.User(item.UserId.ToString()).SendAsync("ReceiveMessage", type, item);
            }
        }

    }
}
